{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"UTF-8\""
      ]
     },
     "execution_count": 78,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### pry-docの読み込み\n",
    "#require \"/root/git_jupyter_notebook/Ruby/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\"\n",
    "require \"/Users/ftakao2007/jupyter/vendor/bundle/ruby/2.3.0/gems/pry-doc-0.10.0/lib/pry-doc\"\n",
    "### エンコーディングをUTF-8に設定\n",
    "Encoding.default_external = \"UTF-8\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# Dirクラス、IOクラス、Fileクラス\n",
    "\n",
    "* Dirクラス\n",
    "    * ディレクトリの移動や作成、ファイル一覧の取得などディレクトリを扱うクラス\n",
    "* IOクラス\n",
    "    * ファイルやプロセスなど入出力を扱うクラス\n",
    "* Fileクラス\n",
    "    * IOクラスの子クラス\n",
    "    * ファイルの読み取りや書き込み、新規作成や削除などファイルを扱うクラス"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Dir, Enumerable, Object, PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]\n",
      "[File, IO, File::Constants, Enumerable, Object, PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]\n"
     ]
    }
   ],
   "source": [
    "puts Dir.ancestors\n",
    "puts File.ancestors"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Dirクラス\n",
    "\n",
    "### ディレクトリを開く、閉じる\n",
    "* メソッド (クラスメソッド)\n",
    "    * Dir.open\n",
    "        * ディレクトリを開く\n",
    "        * 返り値はDirクラスのオブジェクト\n",
    "        * eachメソッドでファイル一覧を取得できる\n",
    "    * Dir.close\n",
    "        * ディレクトリを閉じる"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ディレクトリを開いて一覧表示\n",
      "#<Dir:/tmp>\n",
      "/tmp\n",
      ".\n",
      "..\n",
      ".X11-unix\n",
      ".ICE-unix\n",
      ".XIM-unix\n",
      ".font-unix\n",
      ".Test-unix\n",
      "systemd-private-9fb469dc9a454908abf7a8e8a8419b25-systemd-timesyncd.service-19qSNf\n",
      "basic-checkpoint.ipynb\n",
      "hsperfdata_root\n",
      "\n",
      "ブロックを使ってディレクトリを開くと、処理が終わったとき自動的にCloseする\n",
      "/tmp\n",
      "nil\n"
     ]
    }
   ],
   "source": [
    "puts \"ディレクトリを開いて一覧表示\"\n",
    "dir = Dir.open(\"/tmp\")\n",
    "p dir\n",
    "puts dir.path\n",
    "dir.each{|file| puts file}\n",
    "\n",
    "### ディレクトリを閉じる、一覧表示はできずIOErrorになる\n",
    "dir.close\n",
    "#dir.each{|file| puts file}\n",
    "puts \"\"\n",
    "\n",
    "puts \"ブロックを使ってディレクトリを開くと、処理が終わったとき自動的にCloseする\"\n",
    "dir = Dir.open(\"/tmp\"){|dir| puts dir.path}\n",
    "p dir"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### ディレクトリの操作\n",
    "\n",
    "* メソッド (クラスメソッド)\n",
    "    * Dir.pwd, Dir.getwd\n",
    "        * カレントディレクトリの取得\n",
    "    * Dir.chdir\n",
    "        * ディレクトリの移動\n",
    "    * Dir.mkdir\n",
    "        * ディレクトリの作成\n",
    "    * Dir.rmdir, Dir.unlink, Dir.delete\n",
    "        * ディレクトリの削除"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/tmpでカレントディレクトリの取得\n",
      "/tmp\n",
      "\n",
      "/tmp/tmp2でカレントディレクトリの取得\n",
      "/tmp/tmp2\n",
      "\n",
      "削除後はtmp2ディレクトリ無し\n",
      "\".\"\n",
      "\"..\"\n",
      "\".X11-unix\"\n",
      "\".ICE-unix\"\n",
      "\".XIM-unix\"\n",
      "\".font-unix\"\n",
      "\".Test-unix\"\n",
      "\"systemd-private-9fb469dc9a454908abf7a8e8a8419b25-systemd-timesyncd.service-19qSNf\"\n",
      "\"basic-checkpoint.ipynb\"\n",
      "\"hsperfdata_root\"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "#<Dir:/tmp>"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### /tmpディレクトリに移動\n",
    "Dir.chdir(\"/tmp\")\n",
    "\n",
    "puts \"/tmpでカレントディレクトリの取得\"\n",
    "puts Dir.pwd\n",
    "puts \"\"\n",
    "\n",
    "### 存在していなければ /tmp/tmp2を作成\n",
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "\n",
    "### /tmp/tmp2に移動\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "\n",
    "puts \"/tmp/tmp2でカレントディレクトリの取得\"\n",
    "puts Dir.getwd\n",
    "puts \"\"\n",
    "\n",
    "### 存在していれば/tmp/tmp2ディレクトリを削除\n",
    "Dir.chdir(\"/tmp\")\n",
    "Dir.rmdir(\"/tmp/tmp2\") if Dir.exist?(\"/tmp/tmp2\")\n",
    "#Dir.unlink(\"/tmp/tmp2\") if Dir.exist?(\"/tmp/tmp2\")\n",
    "#Dir.delete(\"/tmp/tmp2\") if Dir.exist?(\"/tmp/tmp2\")\n",
    "\n",
    "puts \"削除後はtmp2ディレクトリ無し\"\n",
    "Dir.open(\"/tmp\").each{|file| p file}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Fileクラス\n",
    "\n",
    "### ファイルを開く、閉じる\n",
    "\n",
    "* メソッド\n",
    "    * File.open, File.new\n",
    "        * ファイルを開く\n",
    "            * デフォルトは読み取りモード\n",
    "            * ファイルオブジェクトが返る\n",
    "                * readメソッドでファイルの内容を取得できる\n",
    "        * <font color=\"red\">引数としてファイル名だけを与えると読み取りモード</font>\n",
    "        * ファイルが存在しない場合はエラー\n",
    "    * File.close\n",
    "        * フィルを閉じる"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"Ruby Association\\nルビーアソシエーション\\nるびー\\nRuby on Rails\\n\"\n",
      "\n",
      "File.openメソッドにブロックを与えると、ブロック終了時に自動的に閉じる\n",
      "Ruby Association\n",
      "ルビーアソシエーション\n",
      "るびー\n",
      "Ruby on Rails\n",
      "\n"
     ]
    }
   ],
   "source": [
    "Dir.chdir(\"/root/git_jupyter_notebook/Ruby\")\n",
    "### 日本語を読み込むためのエンコーディング設定\n",
    "Encoding.default_external = \"UTF-8\"\n",
    "#puts Encoding.default_external\n",
    "\n",
    "### ファイルを読み込む\n",
    "file = File.open(\"sample.txt\")\n",
    "p file.read\n",
    "\n",
    "### ファイルを閉じる\n",
    "file.close\n",
    "puts \"\"\n",
    "\n",
    "puts \"File.openメソッドにブロックを与えると、ブロック終了時に自動的に閉じる\"\n",
    "File.open(\"sample.txt\") do |file|\n",
    "  puts file.read\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### ファイルのモード\n",
    "\n",
    "* r\n",
    "    * 読み込み。デフォルト\n",
    "* w\n",
    "    * 書き込み\n",
    "    * <font color=\"red\">既存のファイルがある場合はファイルの内容を空にする</font>\n",
    "* a\n",
    "    * 追記。常にファイルの末尾に追加される\n",
    "* r+\n",
    "    * 読み書き。<font color=\"red\">ファイルの読み書きの位置が先頭になる</font>\n",
    "* w+\n",
    "    * 読み書き。r+と同じだが、<font color=\"red\">既存のファイルがある場合はファイルの内容が空になる</font>\n",
    "* a+\n",
    "    * 読み書き。読み込みは先頭、書き込みは常に末尾\n",
    "* エンコーディングの指定が可能\n",
    "    * 外部エンコーディング(ファイルのエンコーディング)\n",
    "    * 内部エンコーディング(読み込んだ時のエンコーディング)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### エンコーディングがEUC-JP,Shift-JISのファイル作成\n",
    "\n",
    "```\n",
    "$ cd /tmp\n",
    "$ vi utf-8.txt\n",
    "================================================\n",
    "ルビー\n",
    "================================================\n",
    "\n",
    "$ nkf --guess utf-8.txt\n",
    "================================================\n",
    "UTF-8 (LF)\n",
    "================================================\n",
    "\n",
    "$ nkf -e utf-8.txt > euc-jp.txt\n",
    "$ nkf -s utf-8.txt > shift_jis.txt\n",
    "$ nkf --guess euc-jp.txt\n",
    "================================================\n",
    "EUC-JP (LF)\n",
    "================================================\n",
    "\n",
    "$ nkf --guess shift_jis.txt\n",
    "================================================\n",
    "Shift_JIS (LF)\n",
    "================================================\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "外部エンコーディングがEUC-JPのファイルを読み込んで内部エンコーディングをUTF-8で出力\n",
      "ルビー\n",
      "\n",
      "外部エンコーディングがShift_JISのファイルを読み込んで内部エンコーディングをUTF-8で書き込み\n",
      "るびー\n",
      "\n"
     ]
    }
   ],
   "source": [
    "puts \"外部エンコーディングがEUC-JPのファイルを読み込んで内部エンコーディングをUTF-8で出力\"\n",
    "Dir.chdir(\"/tmp\")\n",
    "f = File.open(\"euc-jp.txt\", \"r:euc-jp:utf-8\")\n",
    "puts f.read\n",
    "f.close\n",
    "\n",
    "puts \"外部エンコーディングがShift_JISのファイルを読み込んで内部エンコーディングをUTF-8で書き込み\"\n",
    "f = File.open(\"shift_jis.txt\", \"w+:shift_jis:utf-8\")\n",
    "### UTF-8にエンコーディング変換\n",
    "#f.write \"ルビー\\n\"\n",
    "f.write 'るびー\\n'.encode('utf-8')\n",
    "f.rewind\n",
    "puts f.read\n",
    "f.close\n",
    "\n",
    "### ただし、ファイル自体のエンコーディングはShift_JISのまま\n",
    "### $ nkf --guess shift_jis.txt\n",
    "### Shift_JIS (LF)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "test.txtファイルの読み込みと表示\n",
      "テスト\n",
      "\n",
      "\n",
      "test.txtファイルの上書き、読み込みと表示\n",
      "てすと\n",
      "\n",
      "\n",
      "test.txtファイルの追記、読み込みと表示\n",
      "てすと\n",
      "テスト追記\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "Dir.chdir(\"/tmp\")\n",
    "\n",
    "puts \"test.txtファイルの読み込みと表示\"\n",
    "File.open(\"test.txt\") do |file|\n",
    "  puts file.read\n",
    "end\n",
    "puts \"\"\n",
    "\n",
    "puts \"test.txtファイルの上書き、読み込みと表示\"\n",
    "File.open(\"test.txt\", \"w\") do |file|\n",
    "  file.write \"てすと\\n\"\n",
    "  ### 書き込みモードなので読み込みはできない (IOError: not opened for reading)\n",
    "  #file.read\n",
    "end\n",
    "File.open(\"test.txt\") do |file|\n",
    "  puts file.read\n",
    "end\n",
    "puts \"\"\n",
    "\n",
    "puts \"test.txtファイルの追記、読み込みと表示\"\n",
    "File.open(\"test.txt\", \"a\") do |file|\n",
    "  file.write \"テスト追記\\n\"\n",
    "  ### 追記モードなので読み込みはできない (IOError: not opened for reading)\n",
    "  #file.read\n",
    "end\n",
    "File.open(\"test.txt\") do |file|\n",
    "  puts file.read\n",
    "end\n",
    "puts \"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "r+\n",
      "\n",
      "testr+.txtファイルの読み込みと表示\n",
      "以下はwrite常に1行目が上書きされてrewindで1行目に戻り、readで結果が読み込まれて表示されている\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "\n",
      "\n",
      "以下はreadで最終行まで読み込まれた後にwriteで最後に書き込まれるため、実行するたびに最後に追記されていく\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "Dir.chdir(\"/tmp\")\n",
    "puts \"r+\"\n",
    "puts \"\"\n",
    "\n",
    "puts \"testr+.txtファイルの読み込みと表示\"\n",
    "puts \"以下はwrite常に1行目が上書きされてrewindで1行目に戻り、readで結果が読み込まれて表示されている\"\n",
    "File.open(\"testr+.txt\", \"r+\") do |file|\n",
    "  file.write \"てすと書き込み\\n\"\n",
    "  file.rewind\n",
    "  puts file.read\n",
    "end\n",
    "puts \"\"\n",
    "\n",
    "puts \"以下はreadで最終行まで読み込まれた後にwriteで最後に書き込まれるため、実行するたびに最後に追記されていく\"\n",
    "File.open(\"testr+.txt\", \"r+\") do |file|\n",
    "  puts file.read\n",
    "  file.write \"てすと書き込み\\n\"\n",
    "  file.rewind\n",
    "  puts file.read\n",
    "end\n",
    "puts \"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "w+\n",
      "\n",
      "testw+.txtファイルの読み込みと表示\n",
      "以下はwrite常に1行目が上書きされてrewindで1行目に戻り、readで結果が読み込まれて表示されている\n",
      "てすと書き込み\n",
      "\n",
      "\n",
      "以下はreadで最終行まで読み込まれた後にwriteで最後に書き込まれる。毎回開いたときにテキストは空の状態\n",
      "(ここのfile.readは何も表示されない) \n",
      "てすと書き込み\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "Dir.chdir(\"/tmp\")\n",
    "puts \"w+\"\n",
    "puts \"\"\n",
    "\n",
    "puts \"testw+.txtファイルの読み込みと表示\"\n",
    "puts \"以下はwrite常に1行目が上書きされてrewindで1行目に戻り、readで結果が読み込まれて表示されている\"\n",
    "File.open(\"testw+.txt\", \"w+\") do |file|\n",
    "  file.write \"てすと書き込み\\n\"\n",
    "  file.rewind\n",
    "  puts file.read\n",
    "end\n",
    "puts \"\"\n",
    "\n",
    "puts \"以下はreadで最終行まで読み込まれた後にwriteで最後に書き込まれる。毎回開いたときにテキストは空の状態\"\n",
    "File.open(\"testw+.txt\", \"w+\") do |file|\n",
    "  ### 開いた直後は空なので以下のfile.readは常時何も表示されない\n",
    "  puts \"(ここのfile.readは何も表示されない) #{file.read}\"\n",
    "  file.write \"てすと書き込み\\n\"\n",
    "  file.rewind\n",
    "  puts file.read\n",
    "end\n",
    "puts \"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a+\n",
      "\n",
      "testa+.txtファイルの読み込みと表示\n",
      "rewindで1行目に戻ってからwriteしているが、a+なので常に末尾に書き込まれる\n",
      "てすと\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "てすと書き込み\n",
      "\n",
      "\n",
      "writeで最後まで移動しているので、rewindしないとreadでファイル内容を表示できない\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "Dir.chdir(\"/tmp\")\n",
    "puts \"a+\"\n",
    "puts \"\"\n",
    "\n",
    "puts \"testa+.txtファイルの読み込みと表示\"\n",
    "puts \"rewindで1行目に戻ってからwriteしているが、a+なので常に末尾に書き込まれる\"\n",
    "File.open(\"testa+.txt\", \"a+\") do |file|\n",
    "  puts file.read\n",
    "  file.rewind\n",
    "  file.write \"てすと書き込み\\n\"\n",
    "end\n",
    "puts \"\"\n",
    "\n",
    "puts \"writeで最後まで移動しているので、rewindしないとreadでファイル内容を表示できない\"\n",
    "File.open(\"testa+.txt\", \"a+\") do |file|\n",
    "  file.write \"てすと書き込み\\n\"\n",
    "  puts file.read\n",
    "end\n",
    "puts \"\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## ファイルの属性を取得する\n",
    "\n",
    "* メソッド (クラスメソッド)\n",
    "    * File.basename\n",
    "        * パスからファイル名を取得する\n",
    "    * File.dirname\n",
    "        * パスからディレクトリ名を取得する\n",
    "    * File.extname\n",
    "        * パスから拡張子を取得する\n",
    "    * File.split\n",
    "        * パスからディレクトリ名とファイル名の配列を取得する\n",
    "    * File.atime\n",
    "        * 最終アクセス時刻を取得する\n",
    "    * File.ctime\n",
    "        * 最終変更時刻を取得する\n",
    "    * File.mtime\n",
    "        * 最終更新時刻を取得する\n",
    "    * File.stat, File.lstat\n",
    "        * File::Statオブジェクトを返す\n",
    "            * 所有者、inode、ブロックサイズやatime,mtime,ctimeなど"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "file_attr.txt\n",
      "/tmp/tmp2\n",
      ".txt\n",
      "[\"/tmp/tmp2\", \"file_attr.txt\"]\n",
      "2017-05-26 01:36:35 +0000\n",
      "2017-05-26 01:44:23 +0000\n",
      "2017-05-26 01:44:23 +0000\n",
      "\n",
      "#<File::Stat dev=0xfd04, ino=46228521, mode=0100644, nlink=1, uid=0, gid=0, rdev=0x0, size=22, blksize=4096, blocks=8, atime=2017-05-26 01:36:35 +0000, mtime=2017-05-26 01:44:23 +0000, ctime=2017-05-26 01:44:23 +0000>\n",
      "2017-05-26 01:36:35 +0000\n"
     ]
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "File.open(\"file_attr.txt\", \"w\") do |file|\n",
    "  file.write \"ファイルの属性\\n\"\n",
    "end\n",
    "\n",
    "puts File.basename(\"/tmp/tmp2/file_attr.txt\")\n",
    "puts File.dirname(\"/tmp/tmp2/file_attr.txt\")\n",
    "puts File.extname(\"/tmp/tmp2/file_attr.txt\")\n",
    "puts File.split(\"/tmp/tmp2/file_attr.txt\")\n",
    "puts File.atime(\"/tmp/tmp2/file_attr.txt\")\n",
    "puts File.ctime(\"/tmp/tmp2/file_attr.txt\")\n",
    "puts File.mtime(\"/tmp/tmp2/file_attr.txt\")\n",
    "puts \"\"\n",
    "\n",
    "# File.lstat(\"/tmp/tmp2/file_attr.txt\")\n",
    "stat1 = File.stat(\"/tmp/tmp2/file_attr.txt\")\n",
    "p stat1\n",
    "puts stat1.atime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/tmp/tmp2/file_attr.txt\n",
      "2017-05-26 01:36:35 +0000\n",
      "2017-05-26 01:44:23 +0000\n",
      "2017-05-26 01:44:23 +0000\n",
      "#<File::Stat dev=0xfd04, ino=46228521, mode=0100644, nlink=1, uid=0, gid=0, rdev=0x0, size=22, blksize=4096, blocks=8, atime=2017-05-26 01:36:35 +0000, mtime=2017-05-26 01:44:23 +0000, ctime=2017-05-26 01:44:23 +0000>\n",
      "\n",
      "[:size, :path, :truncate, :lstat, :atime, :mtime, :ctime, :birthtime, :chmod, :chown, :flock, :to_path, :read_nonblock, :pathconf, :noecho, :nonblock, :nonblock=, :nread, :ready?, :stat, :write_nonblock, :raw, :raw!, :cooked, :cooked!, :getch, :echo=, :echo?, :winsize, :winsize=, :iflush, :oflush, :ioflush, :beep, :goto, :cursor, :cursor=, :pressed?, :getpass, :nonblock?, :wait_readable, :wait_writable, :getbyte, :<<, :wait, :lines, :bytes, :chars, :codepoints, :read, :write, :binmode, :getc, :flush, :readpartial, :set_encoding, :printf, :print, :putc, :puts, :readline, :readlines, :inspect, :gets, :each_line, :each, :each_byte, :each_char, :each_codepoint, :reopen, :to_io, :syswrite, :sysread, :to_i, :fsync, :fileno, :sync, :fdatasync, :lineno, :lineno=, :readchar, :readbyte, :ungetbyte, :ungetc, :sync=, :seek, :tell, :rewind, :pos, :pos=, :eof, :eof?, :close_on_exec?, :close_on_exec=, :close, :closed?, :close_read, :close_write, :isatty, :tty?, :binmode?, :sysseek, :advise, :ioctl, :fcntl, :pid, :external_encoding, :internal_encoding, :autoclose?, :autoclose=, :to_a, :to_h, :include?, :find, :entries, :sort, :sort_by, :grep, :grep_v, :count, :detect, :find_index, :find_all, :select, :reject, :collect, :map, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :first, :all?, :any?, :one?, :none?, :min, :max, :minmax, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :reverse_each, :each_entry, :each_slice, :each_cons, :each_with_object, :zip, :take, :take_while, :drop, :drop_while, :cycle, :chunk, :slice_before, :slice_after, :slice_when, :chunk_while, :lazy, :to_set, :pry, :__binding__, :pretty_print, :pretty_print_cycle, :pretty_print_instance_variables, :pretty_print_inspect, :to_json, :instance_of?, :public_send, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :private_methods, :kind_of?, :instance_variables, :tap, :public_method, :singleton_method, :is_a?, :extend, :define_singleton_method, :method, :to_enum, :enum_for, :<=>, :===, :=~, :!~, :eql?, :respond_to?, :freeze, :display, :object_id, :send, :gem, :to_s, :pretty_inspect, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :trust, :untrusted?, :methods, :protected_methods, :frozen?, :public_methods, :singleton_methods, :!, :==, :!=, :__send__, :equal?, :instance_eval, :instance_exec, :__id__]\n"
     ]
    }
   ],
   "source": [
    "### ファイルオブジェクトのメソッド(インスタンスメソッド)で取得\n",
    "File.open(\"/tmp/tmp2/file_attr.txt\") do |file|\n",
    "  puts file.path\n",
    "  puts file.atime\n",
    "  puts file.ctime\n",
    "  puts file.mtime\n",
    "  p file.stat\n",
    "  puts\n",
    "  puts file.methods\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### ファイルをテストするメソッド"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true\n",
      "true\n",
      "false\n",
      "false\n",
      "false\n",
      "true\n",
      "true\n",
      "25\n"
     ]
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "File.open(\"file_test.txt\", \"w\") do |file|\n",
    "  file.write \"ファイルをテスト\\n\"\n",
    "end\n",
    "\n",
    "puts File.exist?(\"/tmp/tmp2/file_test.txt\")\n",
    "puts File.file?(\"/tmp/tmp2/file_test.txt\")\n",
    "puts File.directory?(\"/tmp/tmp2/file_test.txt\")\n",
    "puts File.symlink?(\"/tmp/tmp2/file_test.txt\")\n",
    "puts File.executable?(\"/tmp/tmp2/file_test.txt\")\n",
    "puts File.readable?(\"/tmp/tmp2/file_test.txt\")\n",
    "puts File.writable?(\"/tmp/tmp2/file_test.txt\")\n",
    "puts File.size(\"/tmp/tmp2/file_test.txt\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### その他ファイルを操作するメソッド\n",
    "\n",
    "* メソッド\n",
    "    * File.chmod\n",
    "        * 権限変更\n",
    "    * File.chown\n",
    "        * 所有者変更\n",
    "    * File.utime\n",
    "        * 最終アクセス時刻、更新時刻を変更\n",
    "            * 第1引数 : 最終アクセス時刻\n",
    "            * 第2引数 : 更新時刻\n",
    "    * File.expand_path\n",
    "        * 絶対パスの取得\n",
    "    * rename\n",
    "        * ファイル名を変更する\n",
    "    * File.truncate\n",
    "        * ファイルを指定したバイト数に切り詰める\n",
    "    * File.delete, File.unlink\n",
    "        * ファイルを削除する\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/tmp/tmp2/file_etc.txt\n",
      "1234567\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 143,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "File.open(\"file_etc.txt\", \"w\") do |file|\n",
    "  file.write \"123456789\\n\"\n",
    "end\n",
    "\n",
    "File.chmod(0644, \"file_etc.txt\")\n",
    "File.chown(1000, 1000, \"file_etc.txt\")\n",
    "File.utime(Time.now, Time.now, \"file_etc.txt\")\n",
    "puts File.expand_path(\"file_etc.txt\")\n",
    "File.rename(\"file_etc.txt\", \"file_etc2.txt\")\n",
    "File.truncate(\"file_etc2.txt\", 7)\n",
    "File.open(\"file_etc2.txt\", \"r\") {|file| puts file.read}\n",
    "File.delete(\"file_etc2.txt\")\n",
    "#File.unlink(\"file_etc2.txt\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 151,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 151,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### 排他ロック\n",
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "File.open(\"file_lock.txt\", \"w\") do |file|\n",
    "  file.write \"sleep中は他のシステムから書き込めない\\n\"\n",
    "  file.flock(File::LOCK_EX)\n",
    "  sleep(10)\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 152,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "45"
      ]
     },
     "execution_count": 152,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### 排他ロック\n",
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "File.open(\"file_lock.txt\", \"a\") do |file|\n",
    "  file.write \"sleepが終わるまで待ってから追記\\n\"\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# IOクラス\n",
    "\n",
    "* IOクラス\n",
    "    * 基本的な入出力機能を備えたクラス\n",
    "    * Fileクラスのスーパークラス\n",
    "        * 多くのメソッドはFileクラスでも利用可能\n",
    "    * 標準入力、標準出力、標準エラー出力もIOクラスのオブジェクト\n",
    "    * Fileクラスと同様\n",
    "        * エンコーディングを指定して開く\n",
    "        * 開いたファイルの読み込みはreadメソッド"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## ファイルを閉じる、開く\n",
    "\n",
    "* メソッド\n",
    "    * <font color=\"red\">Kernelモジュールのopenメソッド</font>\n",
    "        * IO.openメソッドでも同様\n",
    "        * ファイルを開くとファイルオブジェクトが返る\n",
    "        * ファイル名の代わりに|に続いてコマンドを指定するとコマンドの出力結果が得られる\n",
    "    * closeメソッド\n",
    "        * openメソッドでブロックを渡している場合は自動的にファイルは閉じられる"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ファイルを開いて中身を出力\n",
      "ファイルを開く、閉じる\n",
      "\n",
      "コマンドの実行結果を得る\n",
      "total 16\n",
      "-rw-r--r-- 1 root root 22 May 26 01:44 file_attr.txt\n",
      "-rw-r--r-- 1 root root 99 May 26 02:18 file_lock.txt\n",
      "-rw-r--r-- 1 root root 25 May 26 01:59 file_test.txt\n",
      "-rw-r--r-- 1 root root 34 May 26 04:40 io_open.txt\n",
      "\n",
      "ブロックで実行\n",
      "-rw-r--r-- 1 root root   7 May 26 00:42 ../euc-jp.txt\n",
      "-rw-r--r-- 1 root root  22 May 26 01:35 ../file_attr.txt\n",
      "-rw-r--r-- 1 root root   7 May 26 01:00 ../shift_jis.txt\n",
      "-rw-r--r-- 1 root root  26 May 26 01:08 ../test.txt\n",
      "-rw-r--r-- 1 root root 208 May 26 01:27 ../testa+.txt\n",
      "-rw-r--r-- 1 root root 110 May 26 01:18 ../testr+.txt\n",
      "-rw-r--r-- 1 root root  22 May 26 01:23 ../testw+.txt\n",
      "-rw-r--r-- 1 root root  10 May 26 00:41 ../utf-8.txt\n",
      "\n",
      "標準出力に書き込む(Jupyter上ではバイト数が返るだけ)\n",
      "6\n"
     ]
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "File.open(\"io_open.txt\", \"w\") do |file|\n",
    "  file.write \"ファイルを開く、閉じる\\n\"\n",
    "end\n",
    "\n",
    "puts \"ファイルを開いて中身を出力\"\n",
    "io = open(\"io_open.txt\", \"r\")\n",
    "  puts io.read\n",
    "io.close\n",
    "\n",
    "puts \"コマンドの実行結果を得る\"\n",
    "io = open('| ls -l')\n",
    "  puts io.read\n",
    "io.close\n",
    "\n",
    "puts \"ブロックで実行\"\n",
    "open('| ls -l ../*txt') do |io|\n",
    "  puts io.read\n",
    "end\n",
    "\n",
    "puts \"標準出力に書き込む(Jupyter上ではバイト数が返るだけ)\"\n",
    "puts STDOUT.write(\"hello\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## パイプを開く\n",
    "\n",
    "* メソッド\n",
    "    * IO.popen\n",
    "        * コマンドをサブプロセスとして実行し、そのプロセスと入出力のパイプを開くことができる\n",
    "        * <font color=\"red\">openメソッドはコマンドの頭にパイプ|をつけるがpopenはつけない</font>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "io.readの出力結果に対してgrep yしている\n",
      "Ruby \n",
      "Python\n",
      "\n"
     ]
    }
   ],
   "source": [
    "puts \"io.readの出力結果に対してgrep yしている\"\n",
    "IO.popen('grep y', \"r+\") do |io|\n",
    "  io.write(\"Ruby \\nPHP \\nPerl \\nPython\")\n",
    "  io.close_write\n",
    "  puts io.read\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## IOからの入力\n",
    "\n",
    "* メソッド\n",
    "    * IO.read, read\n",
    "        * IOから内容を読み込む\n",
    "        * 長さが指定されていればその長さだけ読み込む\n",
    "        * 空ファイル\n",
    "            * \"\"が返る\n",
    "            * 長さが指定されている場合はnilが返る\n",
    "    * IO.foreach, each, each_line\n",
    "        * 指定されたファイルを開き、各行をブロックに渡して実行していく\n",
    "            * 空ファイル\n",
    "                * IO.foreachはブロックが実行されない\n",
    "                * each, each_lineはEOFであれば何もしない\n",
    "    * readlines\n",
    "        * ファイルをすべて読み込んで各行の<font color=\"red\">配列を返す</font>\n",
    "        * 空ファイルの場合は空の配列が返る\n",
    "    * readline, gets\n",
    "        * 1行読み込む\n",
    "        * 最後まで読み込んだ後にさらに読み取ろうとしたとき\n",
    "            * gets : nilが出る\n",
    "            * readline : エラーになる (EOFError: end of file reached)\n",
    "    * each_byte\n",
    "        * 1バイトずつ整数として読み込んで渡していく\n",
    "        * EOFであれば何もしない\n",
    "    * getbyte, readbyte\n",
    "        * 1バイト読み込んで整数として返す\n",
    "        * 最後まで読み込んだ後にさらに読み取ろうとしたとき\n",
    "            * getbyte : nilが出る\n",
    "            * readbyte : エラーになる (EOFError: end of file reached)\n",
    "    * each_char\n",
    "        * 一文字ずつ読み込んで渡していく\n",
    "    * getc / readchar\n",
    "        * IOオブジェクトから一文字読み込む\n",
    "        * 最後まで読み込んだ後にさらに読み取ろうとしたとき\n",
    "            * getc : nilが出る\n",
    "            * readchar : エラーになる (EOFError: end of file reached)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "IO.read\n",
      "123456789\n",
      "abc\n",
      "xyz\n",
      "5byteだけ読み込み\n",
      "12345\n",
      "\n",
      "read\n",
      "123456789\n",
      "abc\n",
      "xyz\n",
      "\n",
      "foreach\n",
      "\"123456789\\n\"\n",
      "\"abc\\n\"\n",
      "\"xyz\"\n",
      "\n",
      "each\n",
      "\"123456789\\n\"\n",
      "\"abc\\n\"\n",
      "\"xyz\"\n",
      "#<File:0x007fe39914ecc0>\n",
      "\n",
      "each_line\n",
      "\"123456789\\n\"\n",
      "\"abc\\n\"\n",
      "\"xyz\"\n",
      "#<File:0x007fe399115240>\n",
      "\n",
      "readlines\n",
      "[\"123456789\\n\", \"abc\\n\", \"xyz\"]\n",
      "\n",
      "gets\n",
      "\"123456789\\n\"\n",
      "\"abc\\n\"\n",
      "\"xyz\"\n",
      "nil\n",
      "\n",
      "readline\n",
      "\"123456789\\n\"\n",
      "\"abc\\n\"\n",
      "\"xyz\"\n",
      "\n",
      "each_byte\n",
      "49\n",
      "50\n",
      "51\n",
      "52\n",
      "53\n",
      "54\n",
      "55\n",
      "56\n",
      "57\n",
      "10\n",
      "97\n",
      "98\n",
      "99\n",
      "10\n",
      "120\n",
      "121\n",
      "122\n",
      "#<File:0x007fe3990b5ed0>\n",
      "\n",
      "getbyte\n",
      "49\n",
      "50\n",
      "51\n",
      "\n",
      "readbyte\n",
      "49\n",
      "50\n",
      "51\n",
      "\n",
      "each_char\n",
      "\"1\"\n",
      "\"2\"\n",
      "\"3\"\n",
      "\"4\"\n",
      "\"5\"\n",
      "\"6\"\n",
      "\"7\"\n",
      "\"8\"\n",
      "\"9\"\n",
      "\"\\n\"\n",
      "\"a\"\n",
      "\"b\"\n",
      "\"c\"\n",
      "\"\\n\"\n",
      "\"x\"\n",
      "\"y\"\n",
      "\"z\"\n",
      "#<File:0x007fe398f9e178>\n",
      "\n",
      "getc\n",
      "\"1\"\n",
      "\"2\"\n",
      "\"3\"\n",
      "\n",
      "readchar\n",
      "\"1\"\n",
      "\"2\"\n",
      "\"3\"\n",
      "\n"
     ]
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "File.open(\"io_read.txt\", \"w\") do |file|\n",
    "  file.write \"123456789\\nabc\\nxyz\"\n",
    "end\n",
    "puts\n",
    "\n",
    "puts \"IO.read\"\n",
    "puts IO.read(\"io_read.txt\")\n",
    "puts\"5byteだけ読み込み\"\n",
    "puts IO.read(\"io_read.txt\", 5)\n",
    "puts\n",
    "\n",
    "puts \"read\"\n",
    "puts open(\"io_read.txt\").read\n",
    "puts\n",
    "\n",
    "puts \"foreach\"\n",
    "IO.foreach(\"io_read.txt\"){|line| p line}\n",
    "puts\n",
    "\n",
    "puts \"each\"\n",
    "puts open(\"io_read.txt\").each{|line| p line}\n",
    "puts\n",
    "\n",
    "puts \"each_line\"\n",
    "puts open(\"io_read.txt\").each_line{|line| p line}\n",
    "puts\n",
    "\n",
    "puts \"readlines\"\n",
    "puts open(\"io_read.txt\").readlines\n",
    "puts\n",
    "\n",
    "puts \"gets\"\n",
    "io = open(\"io_read.txt\")\n",
    "p io.gets\n",
    "p io.gets\n",
    "p io.gets\n",
    "p io.gets\n",
    "io.close\n",
    "puts\n",
    "\n",
    "puts \"readline\"\n",
    "io = open(\"io_read.txt\")\n",
    "p io.readline\n",
    "p io.readline\n",
    "p io.readline\n",
    "### エラーになるEOFError: end of file reached\n",
    "#p io.readline\n",
    "io.close\n",
    "puts\n",
    "\n",
    "puts \"each_byte\"\n",
    "puts open(\"io_read.txt\").each_byte{|b| p b}\n",
    "puts\n",
    "\n",
    "puts \"getbyte\"\n",
    "io = open(\"io_read.txt\")\n",
    "p io.getbyte\n",
    "p io.getbyte\n",
    "p io.getbyte\n",
    "io.close\n",
    "puts\n",
    "\n",
    "puts \"readbyte\"\n",
    "io = open(\"io_read.txt\")\n",
    "p io.readbyte\n",
    "p io.readbyte\n",
    "p io.readbyte\n",
    "io.close\n",
    "puts\n",
    "\n",
    "puts \"each_char\"\n",
    "puts open(\"io_read.txt\").each_char{|c| p c}\n",
    "puts\n",
    "\n",
    "puts \"getc\"\n",
    "io = open(\"io_read.txt\")\n",
    "p io.getc\n",
    "p io.getc\n",
    "p io.getc\n",
    "io.close\n",
    "puts\n",
    "\n",
    "puts \"readchar\"\n",
    "io = open(\"io_read.txt\")\n",
    "p io.readchar\n",
    "p io.readchar\n",
    "p io.readchar\n",
    "io.close\n",
    "puts"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## IOへの出力\n",
    "\n",
    "* メソッド\n",
    "    * write\n",
    "        * IOに対して引数の文字列を出力する\n",
    "        * <font color=\"red\">出力が成功するとバイト数を返す</font>\n",
    "    * puts\n",
    "        * IOに対して複数のオブジェクトを出力する\n",
    "        * 引数が文字列や配列ではない場合はto_aryメソッドにより配列化し、各要素をto_sメソッドにより文字列化して出力する\n",
    "    * print\n",
    "        * IOに対して複数のオブジェクトを出力する\n",
    "        * 複数のオブジェクトが指定されていると「`$,`」 (出力フィールドの区切り文字)の値を出力する。「`$\\`」(出力レコードの区切り)に値が設定されていれば最後に出力する\n",
    "    * printf\n",
    "        * 指定されたフォーマットに従って引数の値を出力する\n",
    "    * putc\n",
    "        * IOに引数の文字を出力する\n",
    "        * 引数が0〜255の整数の場合は対応する文字を出力する\n",
    "        * 文字列の場合は先頭の1バイトを出力する\n",
    "    * `<<`\n",
    "        * IOに指定されたオブジェクトを出力する\n",
    "        * 返り値がIOオブジェクト自身となる\n",
    "            * メソッドチェーンを使うことができる\n",
    "    * flush\n",
    "        * IOの内部バッファをフラッシュして出力する"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n",
      "nil\n",
      "nil\n",
      "nil\n",
      "nil\n",
      "nil\n"
     ]
    }
   ],
   "source": [
    "p STDOUT.write('abcd')\n",
    "# abcd\n",
    "# => 4\n",
    "p STDOUT.puts('a', 'b')\n",
    "# a\n",
    "# b\n",
    "# nil\n",
    "# => nil\n",
    "\n",
    "p STDOUT.print('a','b')\n",
    "# abnil\n",
    "# => nil\n",
    "\n",
    "$, = \"\\n\"\n",
    "p STDOUT.print('a','b')\n",
    "# a\n",
    "# bnil\n",
    "# => nil\n",
    "\n",
    "$\\ = \"\\n\"\n",
    "p STDOUT.print('a','b')\n",
    "# a\n",
    "# b\n",
    "# nil\n",
    "# => nil\n",
    "\n",
    "p STDOUT.printf('%010d', 12345)\n",
    "# 0000012345nil\n",
    "# => nil\n",
    "\n",
    "puts STDOUT.putc(65)\n",
    "# A65\n",
    "# => nil\n",
    "puts STDOUT.putc(66)\n",
    "# B66\n",
    "# => nil\n",
    "puts STDOUT.putc('ABC')\n",
    "# AABC\n",
    "# => nil\n",
    "\n",
    "STDOUT << \"This\" << \" \" << \"is\" << \" \" << \"README\"\n",
    "# This is README=> #<IO:<STDOUT>>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "flushする前の内容\n",
      "\n",
      "flushした後の内容\n",
      "I have a pen.\n",
      "\n",
      "最終的なテキストの内容\n",
      "I have a pen.\n",
      "I have an apple.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "open(\"io_flush.txt\", \"w\") do |io|\n",
    "  ### この段階ではまだファイルに書き込まれていない\n",
    "  io.write \"I have a pen.\\n\"\n",
    "  puts \"flushする前の内容\"\n",
    "  puts `cat io_flush.txt`\n",
    "  \n",
    "  ### flushすることでファイルに書き込むことができる\n",
    "  io.flush\n",
    "  puts \"flushした後の内容\"\n",
    "  puts `cat io_flush.txt`  \n",
    "\n",
    "  io.write \"I have an apple.\\n\"\n",
    "end\n",
    "\n",
    "puts \"最終的なテキストの内容\"\n",
    "puts `cat io_flush.txt`  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## IOオブジェクトの状態を調べる\n",
    "\n",
    "* オブジェクト\n",
    "    * stat\n",
    "        * IOオブジェクトの状態を返すFile::Statオブジェクトを返す\n",
    "    * closed?\n",
    "        * IOオブジェクトが閉じられたかどうかを調べる\n",
    "    * eof, eof?\n",
    "        * ファイルの終端に到達したかどうかを調べる\n",
    "    * lineno\n",
    "        * 現在の行番号を返す\n",
    "        * Rubyではgetsメソッドが呼び出された回数\n",
    "        * lineno=メソッドで設定することもできる\n",
    "            * <font color=\"red\">変更してもファイルのポインタは変わらない</font>\n",
    "    * sync\n",
    "        * バッファへの書き込みのたびにflushするかどうか\n",
    "            * false : しない(デフォルト)\n",
    "            * true: する"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<File::Stat dev=0x1000002, ino=9098819, mode=0100644, nlink=1, uid=501, gid=0, rdev=0x0, size=0, blksize=4096, blocks=0, atime=2017-05-28 23:11:33 +0900, mtime=2017-05-28 23:12:06 +0900, ctime=2017-05-28 23:12:06 +0900, birthtime=2017-05-28 22:42:12 +0900>\n",
      "ファイルの終端に到達しているのでeof?はtrueを返す\n",
      "true\n",
      "rewindはファイルの終端に到達しているのでeof?はtrueを返す\n",
      "false\n",
      "IOオブジェクトは閉じられていないのでfalseを返す\n",
      "false\n",
      "IOオブジェクトは閉じられたのでtrueを返す\n",
      "true\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"write\""
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "open(\"io_stat.txt\", \"w+\") do |io|\n",
    "  io.write(\"write\")\n",
    "  p io.stat\n",
    "  puts \"ファイルの終端に到達しているのでeof?はtrueを返す\"\n",
    "  puts io.eof?\n",
    "  io.rewind\n",
    "  puts \"rewindはファイルの終端に到達しているのでeof?はtrueを返す\"\n",
    "  puts io.eof?\n",
    "  puts \"IOオブジェクトは閉じられていないのでfalseを返す\"\n",
    "  puts io.closed?\n",
    "  io.close\n",
    "  puts \"IOオブジェクトは閉じられたのでtrueを返す\"\n",
    "  puts io.closed?\n",
    "end\n",
    "\n",
    "`cat io_stat.txt`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "\"line1\\n\"\n",
      "1\n",
      "\"line2\\n\"\n",
      "2\n",
      "\"line3\\n\"\n",
      "rewindで最初に戻る\n",
      "0\n",
      "\"line1\\n\"\n",
      "1\n",
      "\"line2\\n\"\n",
      "2\n",
      "\"line3\\n\"\n",
      "lineno=1を実行。linenoは1になっているが、ポインタの位置は3(line4)のまま\n",
      "1\n",
      "\"line4\\n\"\n",
      "2\n",
      "\"line5line1\\n\"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"line5line1\\n\""
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "open(\"io_lineno.txt\", \"a+\") do |io|\n",
    "  #  io.write(\"line1\\nline2\\nline3\\nline4\\nline5\")\n",
    "  puts io.lineno\n",
    "  p io.gets\n",
    "  puts io.lineno\n",
    "  p io.gets\n",
    "  puts io.lineno\n",
    "  p io.gets\n",
    "\n",
    "  puts \"rewindで最初に戻る\"\n",
    "  io.rewind\n",
    "  p io.lineno\n",
    "  p io.gets\n",
    "  p io.lineno\n",
    "  p io.gets\n",
    "  p io.lineno\n",
    "  p io.gets\n",
    "  \n",
    "  puts \"lineno=1を実行。linenoは1になっているが、ポインタの位置は3(line4)のまま\"\n",
    "  io.lineno=1\n",
    "  p io.lineno\n",
    "  p io.gets\n",
    "  p io.lineno\n",
    "  p io.gets\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "デフォルトはfalse\n",
      "false\n",
      "\n",
      "trueに変更\n",
      "true\n",
      "\n",
      "バッファ書き込み直後にファイルへ書き出し1\n",
      "line1\n",
      "\n",
      "バッファ書き込み直後にファイルへ書き出し2\n",
      "line1\n",
      "line2\n",
      "\n",
      "最終出力結果\n",
      "line1\n",
      "line2\n",
      "\n"
     ]
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "open(\"io_sync.txt\", \"w+\") do |io|\n",
    "  puts \"デフォルトはfalse\"\n",
    "  puts io.sync\n",
    "  puts \n",
    "  puts \"trueに変更\"\n",
    "  puts io.sync = true\n",
    "  puts\n",
    "  io.write(\"line1\\n\")\n",
    "  puts \"バッファ書き込み直後にファイルへ書き出し1\"\n",
    "  puts `cat io_sync.txt`\n",
    "  io.write(\"line2\\n\")\n",
    "  puts \"バッファ書き込み直後にファイルへ書き出し2\"\n",
    "  puts `cat io_sync.txt`\n",
    "end\n",
    "\n",
    "puts \"最終出力結果\"\n",
    "puts `cat io_sync.txt`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## ファイルポインタの移動や設定\n",
    "\n",
    "* メソッド\n",
    "    * rewind\n",
    "        * ファイルポインタを先頭に移動する\n",
    "        * linenoを0に設定する\n",
    "    * pos\n",
    "        * <font color=\"red\">現在のファイルポインタの位置を取得、設定する</font>\n",
    "        * 行ではなくバイト単位(?)で進む\n",
    "    * seek\n",
    "        * 指定した数だけファイルポインタを2番目の引数の位置から移動する\n",
    "            * 設定可能な位置\n",
    "                * IO::SEEK_SET\n",
    "                    * ファイルの先頭からの位置\n",
    "                * IO::SEEK_CUR\n",
    "                    * 現在のファイルポインタの位置 (デフォルト)\n",
    "                * IO::SEEK_END\n",
    "                    * ファイルの末尾"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "line1\n",
      "\n",
      "2\n",
      "\"ne1\\n\"\n",
      "\"line2\\n\"\n",
      "6\n",
      "\"line2\\n\"\n",
      "14\n",
      "\"ne3\\n\"\n",
      "\"line4\\n\"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"line1\\nline2\\nline3\\nline4\\nline5\""
      ]
     },
     "execution_count": 117,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "open(\"io_pos.txt\", \"r\") do |io|\n",
    "#   io.write(\"line1\\nline2\\nline3\\nline4\\nline5\")\n",
    "  puts io.pos\n",
    "  puts io.gets\n",
    "  puts io.pos = 2\n",
    "  p io.gets\n",
    "  p io.gets\n",
    "  puts io.pos = 6\n",
    "  p io.gets\n",
    "  puts io.pos = 14\n",
    "  p io.gets\n",
    "  p io.gets\n",
    "end\n",
    "\n",
    "`cat io_rewind.txt`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 150,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "IO::SEEK_SET\n",
      "\"ne3\\n\"\n",
      "\n",
      "IO::SEEK_CUR\n",
      "\"ine3\\n\"\n",
      "\n",
      "IO::SEEK_END\n",
      "\"ine4\\nline5\"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"ine4\\nline5\""
      ]
     },
     "execution_count": 150,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Dir.mkdir(\"/tmp/tmp2\", 0755) unless Dir.exist?(\"/tmp/tmp2\")\n",
    "Dir.chdir(\"/tmp/tmp2\")\n",
    "open(\"io_seek.txt\", \"r\") do |io|\n",
    "#io.write(\"line1\\nline2\\nline3\\nline4\\nline5\")\n",
    "  \n",
    "  puts \"IO::SEEK_SET\"\n",
    "  #io.seek(14)\n",
    "  io.seek(14, IO::SEEK_SET)\n",
    "  p io.gets\n",
    "  puts \n",
    "  \n",
    "  puts \"IO::SEEK_CUR\"\n",
    "  io.seek(-5, IO::SEEK_CUR)\n",
    "  p io.gets\n",
    "  puts \n",
    "  \n",
    "  puts \"IO::SEEK_END\"\n",
    "  io.seek(-10, IO::SEEK_END)\n",
    "  p io.read\n",
    "end\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Ruby 2.3.1",
   "language": "ruby",
   "name": "ruby"
  },
  "language_info": {
   "file_extension": ".rb",
   "mimetype": "application/x-ruby",
   "name": "ruby",
   "version": "2.3.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
